<?php

namespace api\components\dataCenter;

use Generator;
use Yii;

class AsycnDownloadService
{
    const CACHE_NAMESPACE = 'AsycnDownload:';

    //创建下载任务
    const CREATE_DOWNLOAD_TASK_API = '/district-fe-api/supply/create-download-task';
    //下载离线任务
    const DOWNLOAD_DATA_API = '/district-fe-api/supply/download';
    //查询下载任务
    const GET_DOWNLOAD_TASK_LIST = '/district-fe-api/supply/query';
    //查询任务状态
    const GET_TASK_STATUS = '/district-fe-api/supply/fetch-task-status';

    const TASK_STATUS_NEW = 'new';
    const TASK_STATUS_RUNNING = 'running';
    const TASK_STATUS_FINISHED = 'finished';

    private $base_uri;

    public function __construct()
    {
        $this->base_uri = Yii::$app->params['asycn_download_api']['base_uri'];
    }

    /**
     * 单次 request
     * @param $host
     * @param $url
     * @param $method
     * @param array $params
     * @param array $body
     * @param bool $json
     * @param int $timeout
     * @return array
     */
    private function _request($url, $method, $params = [], $body = [])
    {
        $url = $this->base_uri . $url;
        $params['token'] = Yii::$app->params['asycn_download_api']['key'];
        !empty($params) && $url = $url . '?' . http_build_query($params);

        $response = Yii::$app->curl->$method($url, $body);
    }

    /**
     * 创建下载任务
     * @param $params
     * @param null|string $district_code
     * @param null|string $town_code
     * @param null|string|int $uid
     * @param string|null $cron
     * @return array
     */
    public function createDownloadTask($params, ?string $district_code = null, ?string $town_code = null, $uid = null, ?string $cron = null)
    {
        unset($params['limit']);
        unset($params['offset']);
        $district_code && $params['district_code'] = $district_code;
        $town_code && $params['town_code'] = $town_code;
        $uid && $params['create_user'] = strval($uid);
        $cron && $params['cron'] = $cron;

        /**
         * 缓存机制
         * 离线下载有判重机制，若请求参数一致则不会返回结果
         * 这里做一个15分钟缓存，若15分钟内有相同的请求参数，则直接拿缓存中的返回结果，否则添加附加参数req_time保证请求参数不会一致
         */
        $cache_key = $this->downloadTaskCacheKey($params);
        $redis = Yii::$app->redis;
        $result = $redis->get($cache_key);
        if ($result) {
            return json_decode($result, true);
        } else {
            $request_params = array_merge($params, ['req_time' => strval(time()) . strval(mt_rand(0, 9999))]);
            $result = $this->_request(static::CREATE_DOWNLOAD_TASK_API, 'get', $request_params);
            $redis->set($cache_key, json_encode($result), 60 * 10);
            return $result;
        }
    }

    private function downloadTaskCacheKey($params)
    {
        return static::CACHE_NAMESPACE . 'task:' . md5(json_encode($params));
    }

    /**
     * 下载数据
     * 鉴于有时数据量过大，此处为分行返回数据
     * @param string|int $task_id
     * @return Generator
     */
    public function downloadData($task_id)
    {
        $params = ['task_id' => $task_id, 'token' => Yii::$app->params['asycn_download_api']['key']];
        $url = $this->base_uri . static::DOWNLOAD_DATA_API . '?' . http_build_query($params);
        $options = [
            'ssl' => [
                'verify_peer' => false,
                'verify_peer_name' => false
            ]
        ];
        $ori_file = new \SplFileObject($url, 'rb', false, stream_context_create($options));

        while (!$ori_file->eof()) {
            yield trim($ori_file->fgets());
        }
    }

//    /**
//     * 获取任务列表（默认获取已完成列表）
//     * @param array $task_id
//     * @param string|null $status
//     * @return array
//     */
//    public function getTaskList(array $task_id, ?string $status = self::TASK_STATUS_FINISHED)
//    {
//        if (empty($task_id)) return [];

//        $params = ['task_ids' => implode(',', $task_id)];
//        $status && $params['status'] = $status;
//        $result = $this->_request($this->base_uri, static::GET_DOWNLOAD_TASK_LIST, 'get', $params);
//        return $result['data'] ?? [];
//    }

    public function getTaskStatus($task_id)
    {
        if (empty($task_id)) return static::TASK_STATUS_NEW;
        $params = ['task_id' => $task_id];
        $result = $this->_request(static::GET_TASK_STATUS, 'get', $params);
        return $result['status'] ?? static::TASK_STATUS_NEW;
    }
}
